dim F$( 10 ), FC$( 9 ), P( 8 ), G( 8, 10 )
F$ will be the player data for the dropping piece.
FC$ will be blank player data to erase the dropping piece. I could have stuffed this into F$, but whatevs.
Array P is the number of pieces in each column. If P(1) = 4 then there are four pieces stacked in the leftmost column.
Two-dimensional array G keeps track of the Grid of piece locations.
T = 1

T is whose turn it is, switches between 0 (for player 1) and 1 (for player 2.)
graphics 7
F = adr( F$ )
FC = adr( FC$ )
FC$ = \00\00\00\00\00\00\00\00\00
print Welcome to Connect 4

Set up the screen, and get the memory locations for the game piece player (F) and the blank game piece player (FC.) Set FC$ to all 0s. 
A = peek( 106 ) - 32
poke 54279, A
PM = 256 * A
poke 559, 46
poke 53277, 3
poke 623, 4
poke 53248, 100
poke 53256, 0
poke 53257, 1
poke 704, 55
poke 53248, 155

Setting up player-missile graphics. I have to re-learn this every time. Im sorry, I dont feel like explaining every line. This article is super helpful: http://www.atarimagazines.com/v2n6/playermissile.html
for I = 0 to 4 * 128
dpoke PM + I * 2, 0
next I

Clear the PM memory area.
F$ = \00\10|\FE\FE\FE\FE\FE|\10

Heres the ATASCII mess for the piece to drop.
color 3
for Y = 10 to 70 step 10
for X = 110 to 40 step -10
circle X, Y, 5
next X
next Y

Draw the board. Right to left because why not.
while 1

The main loop happens forever until someone wins or ties.
T = not T

Switch from player 0 to 1 or vice versa.
color T + 1
M = M + 1

M is number of moves, a.k.a. turn number.
print Player ; T + 1; s turn
if M = 57
print TIE GAME
sound 0, 200, 10, 8
pause 6
sound 
while strig( T )
wend 
clr 
run 
endif 

If its turn 57 the board must be full, game over. Print message, trigger to restart.
Next we let the player choose where to drop her piece using the joystick.
X = 0
while X = 0
X = 4
X is the column number. Start in the middle(ish) with 4.
if T
poke 704, 202
else 
poke 704, 40
endif

Change the color of the piece depending on player 0 or 1.

move F, PM + 522, 10

Set the vertical position of the piece to drop above the board.
while strig( T )

Until the players joystick trigger isuh, triggered:
poke 53248, 75 + 10 * X

Set the horizontal position of the piece.
X = X + ( stick( T ) = 7 ) - ( stick( T ) = 11 )

Increment or decrement X depending on joystick left or right. This is so elegant. An old technique, I didnt think of it.
if X < 1
X = 8
endif 
if X > 8
X = 1
endif

Scolling off the side goes around to the other side. 
pause 4
Its too fast without this.
wend 


if P( X ) = 7
sound 0, 99, 6, 8
pause 5
sound 
X = 0
endif

Did the player pick a column thats already full? Play a buzz and set X back to 0 to make her do it again. (What happens without this check is rather funny.)
wend 

OK, the player trigged the trigger.
P( X ) = P( X ) + 1
Theres one more piece in the chosen column.
G( X, P( X ) ) = T + 1

Make note of the piece in the Grid of pieces. Using 1 for player 1, 2 for player 2, 0 for no piece.
for I = PM + 512 + 10 to PM + 512 + 91 - P( X ) * 10
move F, I, 10
poke 53248, 75 + 10 * X
next I

The piece is represented by Player 0 at this point. Drop it into place by redrawing it one line lower again and again. Because the top row of the player is blank, it automatically erases the old player data from memory as it moves down. 
paint 30 + ( 10 * X ), 80 - 10 * P( X )

Now that the Player 0 is in its place on the board, it cant stay there forever - well reuse it for the next turn. So use TBXLs fun PAINT function to fill in the circle on the game board
poke 53248, 0

Then hide Player 0 way off beyond the left side of the screen. Fun slight-of-hand to replace Player 0 with the PAINTed in graphics.
move FC, PM + 512 + 92 - P( X ) * 10, 9

Blank the old player piece from Player 0 by overwriting it with the 0s contained in FC$.
if P( X ) > 3
if G( X, P( X ) ) & G( X, P( X ) - 1 ) & G( X, P( X ) - 2 ) & G( X, P( X ) - 3)
goto 200
endif 
endif
If theres 4 or more pieces in the chosen column, check to see if theyre all the current players color: if so, its a vertical win.
for X = 1 to 5
for Y = 1 to 7

Brute-forcedly iterate over the board looking for other wins.
if G( X, Y )
Dont bother if theres no piece here.
if G( X, Y ) & G( X + 1, Y ) & G( X + 2, Y ) & G( X + 3, Y )
goto 200
endif
Is it horizontal?
if G( X,Y ) & G( X + 1, Y + 1 ) & G( X + 2, Y + 2 ) & G( X + 3, Y + 3)
goto 200
endif
Is it diagonal going up and right?
if Y > 3
if G( X,Y ) & G( X+1, Y - 1 ) & G( X + 2, Y - 2 ) & G( X + 3, Y-3)
goto 200
endif 
endif 
Is it diagonal going down and right?
endif 
next Y
next X

wend

Aaaand back to the start of the main loop. Using WHILE(1)WEND is a pleasant way to avoid a GOTO statement which is important when making 10-line programs.
200
Heres the only gotta-have-it line number, the place to GOTO when theres a win.
print PLAYER ; T + 1;  WINS!
for X = 1 to 255
poke 708 + T, X
sound 0, rand( 255 ), 10, 10
next X

Print a message, light up the winners pieces, play a happy sound.
sound 
while strig( T )
wend 
clr 
run 
Wait for winner to trigger the trigger, and reset to play again.

